`timescale 1ns / 1ps
/*
 Copyright 2020 Sean Xiao, jxzsxsp@qq.com
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

module csr_mcause
(
    input  sys_clk,

    input  i_irq_src,
    input  i_mie,

    input  i_meie,
    input  i_mtie,
    input  i_msie,
 
    input  i_sft_irq,
    input  i_tmr_irq,
    input  i_ext_irq,

    input  i_EXE_vld,
    input  i_acc_dis,
    input  [ 11: 0 ] i_csr_addr,
    input  [ 31: 0 ] i_csr_val,
    input  i_csr_wen,

    input  i_exp_src,
    input  i_iam_exp,
    input  i_iaf_exp,
    input  i_illi_exp,
    input  i_bp_exp,
    input  i_mti_exp,
    input  i_lam_exp,
    input  i_laf_exp,
    input  i_saam_exp,
    input  i_saaf_exp,

    output [ 31: 0 ] o_mcause,

    input  rst_n
);

/*
mcause : Machine Cause Register    RW
XLEN-1     XLEN-2                              0
--------------------------------------------------
interrupt  |            exception code (WLRL)
--------------------------------------------------
1                       XLEN-1

Interrupt Exception Code Description
--------------------------------------------------
1   0 User software interrupt
1   1 Supervisor software interrupt
1   2 Reserved for future standard use
1   3 Machine software interrupt
--------------------------------------------------
1   4 User timer interrupt
1   5 Supervisor timer interrupt
1   6 Reserved for future standard use
1   7 Machine timer interrupt
--------------------------------------------------
1   8 User external interrupt
1   9 Supervisor external interrupt
1   10 Reserved for future standard use
1   11 Machine external interrupt
--------------------------------------------------
1   12–15 Reserved for future standard use
1   ≥16 Reserved for platform use
--------------------------------------------------
0   0 Instruction address misaligned
0   1 Instruction access fault
0   2 Illegal instruction
0   3 Breakpoint
0   4 Load address misaligned
0   5 Load access fault
0   6 Store/AMO address misaligned
0   7 Store/AMO access fault
0   8 Environment call from U-mode
0   9 Environment call from S-mode
0   10 Reserved
0   11 Environment call from M-mode
0   12 Instruction page fault
0   13 Load page fault
0   14 Reserved for future standard use
0   15 Store/AMO page fault
0   16–23 Reserved for future standard use
0   24–31 Reserved for custom use
0   32–47 Reserved for future standard use
0   48–63 Reserved for custom use
0   ≥64 Reserved for future standard use
--------------------------------------------------

*/


wire m_is = i_mie & i_msie & i_sft_irq;
wire m_it = i_mie & i_mtie & i_tmr_irq;
wire m_ie = i_mie & i_meie & i_ext_irq;
//===============================================================================
wire [31:0] exp_mcause;
    assign exp_mcause[31:5] = 27'b0;
    assign exp_mcause[4:0]  = 
      i_iam_exp     ? 5'd0 //Instruction address misaligned
    : i_iaf_exp     ? 5'd1 //Instruction access fault
    : i_illi_exp    ? 5'd2 //Illegal instruction
    : i_bp_exp      ? 5'd3 //Breakpoint
    : i_lam_exp     ? 5'd4 //load address misalign
    : i_laf_exp     ? 5'd5 //load access fault
    : i_saam_exp    ? 5'd6 //Store/AMO address misalign
    : i_saaf_exp    ? 5'd7 //Store/AMO access fault
    : 5'h1F;               //Otherwise a reserved value


wire [31:0] irq_mcause;
    assign irq_mcause[31]   = 1'b1;
    assign irq_mcause[30:4] = 27'b0;
    assign irq_mcause[3:0]  =   m_is ? 4'd3  :  // 3  Machine software interrupt
                                m_it ? 4'd7  :  // 7  Machine timer interrupt
                                m_ie ? 4'd11 :  // 11 Machine external interrupt
                                4'b0;

wire [31:0] mcause_val = i_irq_src ? irq_mcause : exp_mcause;
//===============================================================================
wire mcause_valid = (i_irq_src | i_exp_src) ? 1'b1 : 1'b0;

wire wbck_csr_wen = i_csr_wen & ( ~i_acc_dis );
wire sel_mcause   = (i_csr_addr == 12'h342);
wire wr_mcause    = sel_mcause & wbck_csr_wen;
wire mcause_ena   = wr_mcause | mcause_valid;

wire [31:0] mcause_r;
wire [31:0] mcause_nxt = mcause_valid ? mcause_val : i_csr_val;

yue_dfflr #(32) mcause_dfflr (mcause_ena, mcause_nxt, mcause_r, sys_clk, rst_n);

assign o_mcause = mcause_r;


endmodule
